package com.wwj.utils;

import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.RandomUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Date;

public class IDCenterUtil {
	public static final Logger logger = LoggerFactory.getLogger(IDCenterUtil.class);
	
	// private static IdCenterUtil instance = null;

	private IDCenterUtil() {
	}

	// 内部静态类方式
	private static class SingletonHolder {
		private static final IDCenterUtil INSTANCE = new IDCenterUtil();
	}

	public static final IDCenterUtil getInstance() {
		return SingletonHolder.INSTANCE;
	}

	//
	// public synchronized static IdCenterUtil getInstance() {
	// if (instance == null) {
	// synchronized (IdCenterUtil.class) {
	// if (instance == null) {
	// try {
	// instance = new IdCenterUtil();
	// instance.initParam();
	// } catch (Exception e) {
	// logger.error("", e);
	// }
	// }
	// }
	// }
	// return instance;
	// }

	/**
	 * 获取ip第几位 从1开始
	 * 
	 * @param flag
	 * @return
	 */
	public Long getIpFlag(int flag) {
		String ip = IpUtil.getLocalIP();
		// logger.info("ip=" + ip);
		String ips[] = ip.split("[.]");
		return Long.valueOf(ips[flag - 1]);
	}

	/**
	 * 节点 ID 默认取1
	 */
	private long workerId = 1;
	/**
	 * 数据中心的ID 默认取1
	 */
	private long datacenterId = 1;
	/**
	 * 序列id 默认取1
	 */
	private long sequence = 1;
	/**
	 * 起始纪元
	 */
	private long idepoch = 1379314066953l;
	/**
	 * 机器标识位数
	 */
	private final long workerIdBits = 5L;
	/**
	 * 数据中心标识位数
	 */
	private final long datacenterIdBits = 5L;
	/**
	 * 机器ID最大值
	 */
	private final long maxWorkerId = -1L ^ (-1L << workerIdBits);
	/**
	 * 数据中心ID最大值
	 */
	private final long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
	/**
	 * 毫秒内自增位
	 */
	private final long sequenceBits = 12L;
	/**
	 * 机器ID偏左移12位
	 */
	private final long workerIdShift = sequenceBits;
	/**
	 * 数据中心ID左移17位
	 */
	private final long datacenterIdShift = sequenceBits + workerIdBits;
	/**
	 * 时间毫秒左移22位
	 */
	private final long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
	private final long sequenceMask = -1L ^ (-1L << sequenceBits);

	private long lastTimestamp = -1L;

	public void initParam() {
		if (workerId < 0 || workerId > maxWorkerId) {
			throw new IllegalArgumentException("workerId is illegal: " + workerId);
		}
		if (datacenterId < 0 || datacenterId > maxDatacenterId) {
			throw new IllegalArgumentException("datacenterId is illegal: " + workerId);
		}
		workerId = getIpFlag(3);
		datacenterId = getIpFlag(4);
	}

	public long getDatacenterId() {
		return datacenterId;
	}

	public long getWorkerId() {
		return workerId;
	}

	public long getTime() {
		return System.currentTimeMillis();
	}

	public long getId() {
		long id = nextId2();
		return id;
	}

	/**
	 * 获取id 线程安全
	 * 
	 * @return
	 */
	public synchronized long nextId() {
		long timestamp = timeGen();
		// 时间错误
		if (timestamp < lastTimestamp) {
			throw new IllegalStateException("Clock moved backwards.");
		}
		// 当前毫秒内，则+1
		if (lastTimestamp == timestamp) {
			// 当前毫秒内计数满了，则等待下一秒
			sequence = (sequence + 1) & sequenceMask;
			if (sequence == 0) {
				timestamp = tilNextMillis(lastTimestamp);
			}
		} else {
			sequence = 0;
		}
		lastTimestamp = timestamp;
		// ID偏移组合生成最终的ID，并返回ID
		long id = ((timestamp - idepoch) << timestampLeftShift) | (datacenterId << datacenterIdShift) | (workerId << workerIdShift) | sequence;
		return id;
	}

	/**
	 * 获取id 线程安全
	 * 
	 * @return
	 */
	private synchronized long nextId2() {
		long timestamp = timeGen();
		// 时间错误
		if (timestamp < lastTimestamp) {
			throw new IllegalStateException("Clock moved backwards.");
		}
		// 当前毫秒内，则+1
		if (lastTimestamp == timestamp) {
			// 当前毫秒内计数满了，则等待下一秒
			sequence = (sequence + 1) & sequenceMask;
			if (sequence == 0) {
				timestamp = tilNextMillis(lastTimestamp);
			}
		} else {
			sequence = 0;
		}
		lastTimestamp = timestamp;
		// ID偏移组合生成最终的ID，并返回ID
		long id = ((timestamp - idepoch) << timestampLeftShift) | (datacenterId << datacenterIdShift) | (workerId << workerIdShift) | sequence;
		if (workerId == 0)
			workerId = datacenterId;
		String str = Long.toString(workerId).concat(Long.toString(datacenterId));
		if (str.length() > 4) {
			str = StringUtils.substring(str, 0, 4);
		} else {
			while (str.length() != 4) {
				str = str.concat(Integer.toString(RandomUtils.nextInt(0,10)));
			}
		}
		String tail = RandomStringUtils.randomNumeric(4);
		return Long.parseLong(str.concat(StringUtils.substring(Long.toString(id), 7)).concat(tail));
	}

	/**
	 * 等待下一个毫秒的到来
	 * 
	 * @param lastTimestamp
	 * @return
	 */
	private long tilNextMillis(long lastTimestamp) {
		long timestamp = timeGen();
		while (timestamp <= lastTimestamp) {
			timestamp = timeGen();
		}
		return timestamp;
	}

	public String generateOrderId(){
		String id = getId()+"";
		int length = id.length();
		String idSuffix = new String(id).substring(length - 6, length);
		try {
			String dateStr = DateUtil.convertDate2String(DateUtil.ID_DATETIME_FORMAT, new Date());
			return dateStr + idSuffix;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return "";
	}

	private long timeGen() {
		return System.currentTimeMillis();
	}

	public static void main(String[] args) {
		System.out.println(IDCenterUtil.getInstance().generateOrderId());
		System.out.println(IDCenterUtil.getInstance().generateOrderId().length());
		//Long l = IdCenterUtil.getInstance().getIpFlag(3);
		//System.out.println(l);
	}

}